namespace UnitTests
{
    using System;
    using System.Collections.Specialized;
    using System.Web;
    using System.Web.Security;
    using FormStateKeeper;
    using NUnit.Framework;
    using UnitTests.Foundation;
    using It = Moq.It;

    [TestFixture]
    public class FormStateKeeperModuleTests : BaseTestFixture
    {
        [Test]
        public void OnBeginRequest_HttpGet_NoCookieSet()
        {
            using (var context = Setup.TestContext<WebTestContext>()
                .WithScenario(WebScenarios.HttpGet)
                .Create())
            {
                var sut = new FormStateKeeperModuleForTest();
                sut.AnonymousAccessResult = false;
                sut.OnInit("loginUrl", "formsAuthCookieName");

                sut.OnBeginRequest(context.HttpContextMock.Object);

                Assert.Null(context.ResponseMock.Object.Cookies[sut.CookieName]);
            }
        }

        [Test]
        public void OnBeginRequest_PostAndValidAuth_NoCookieSet()
        {
            using (var context = Setup.TestContext<WebTestContext>()
                .WithScenario(WebScenarios.ValidFormsAuthentication)
                .WithScenario(WebScenarios.HttpPost)
                .Create())
            {
                var sut = new FormStateKeeperModuleForTest();
                sut.AnonymousAccessResult = false;
                sut.OnInit("loginUrl", "formsAuthCookieName");

                sut.OnBeginRequest(context.HttpContextMock.Object);

                Assert.Null(context.ResponseMock.Object.Cookies[sut.CookieName]);
            }
        }

        [Test]
        public void OnBeginRequest_PostAndAuthExpired_ResponseHasCookie()
        {
            using (var context = Setup.TestContext<WebTestContext>()
                .WithScenario(WebScenarios.ExpiredFormsAuthentication)
                .WithScenario(WebScenarios.HttpPost)
                .Create())
            {
                var sut = new FormStateKeeperModuleForTest();
                sut.AnonymousAccessResult = false;
                sut.OnInit("loginUrl", "formsAuthCookieName");

                sut.OnBeginRequest(context.HttpContextMock.Object);

                Assert.NotNull(context.ResponseMock.Object.Cookies[sut.CookieName]);
            }
        }

        [Test]
        public void OnBeginRequest_FormPostAndAuthExpired_FormStateStored()
        {
            using (var context = Setup.TestContext<WebTestContext>()
                .WithScenario(WebScenarios.ExpiredFormsAuthentication)
                .WithScenario(WebScenarios.HttpPost)
                .WithScenario(WebScenarios.RequestFormWith, "myField", "myValue")
                .Create())
            {
                var sut = new FormStateKeeperModuleForTest();
                sut.AnonymousAccessResult = false;
                sut.OnInit("loginUrl", "formsAuthCookieName");

                sut.OnBeginRequest(context.HttpContextMock.Object);
                FormState state = FormState.Load(context.ResponseMock.Object.Cookies[sut.CookieName].Value);

                Assert.NotNull(state);
            }
        }

        [Test]
        public void OnBeginRequest_FormPostAndAuthExpired_FormContentsStoredInFormState()
        {
            using (var context = Setup.TestContext<WebTestContext>()
                .WithScenario(WebScenarios.ExpiredFormsAuthentication)
                .WithScenario(WebScenarios.HttpPost)
                .WithScenario(WebScenarios.RequestFormWith, "myField", "myValue")
                .Create())
            {
                var sut = new FormStateKeeperModuleForTest();
                sut.AnonymousAccessResult = false;
                sut.OnInit("loginUrl", "formsAuthCookieName");

                sut.OnBeginRequest(context.HttpContextMock.Object);
                FormState state = FormState.Load(context.ResponseMock.Object.Cookies[sut.CookieName].Value);

                Assert.AreEqual("myValue", state.Form["myField"]);
            }
        }

        [Test]
        public void OnBeginRequest_FormPostAndAuthExpired_RequestPathStoredInFormState()
        {
            using (var context = Setup.TestContext<WebTestContext>()
                .WithScenario(WebScenarios.ExpiredFormsAuthentication)
                .WithScenario(WebScenarios.HttpPost)
                .WithScenario(WebScenarios.RequestFormWith, "myField", "myValue")
                .WithScenario(WebScenarios.RequestPathIs, "someUrl")
                .Create())
            {
                var sut = new FormStateKeeperModuleForTest();
                sut.AnonymousAccessResult = false;
                sut.OnInit("loginUrl", "formsAuthCookieName");

                sut.OnBeginRequest(context.HttpContextMock.Object);
                FormState state = FormState.Load(context.ResponseMock.Object.Cookies[sut.CookieName].Value);

                Assert.AreEqual("someUrl", state.Path);
            }
        }

        [Test]
        public void OnPostMapRequestHandler_CurrentFormStatePresent_SetsRestoreHandler()
        {
            using (var context = Setup.TestContext<WebTestContext>()
                .Create())
            {
                context.RequestMock.Object.Form.Add("myField", "myValue");
                FormState state = FormState.Create(context.HttpContextMock.Object);
                var sut = new FormStateKeeperModuleForTest();
                sut.OnInit("loginUrl", "formsAuthCookieName");
                context.RequestMock.Object.Cookies.Add(new HttpCookie(sut.CookieName, state.StateId));

                sut.OnPostMapRequestHandler(context.HttpContextMock.Object);

                context.HttpContextMock.VerifySet(mock => mock.Handler = It.IsAny<FormStateRestoreHandler>());
            }
        }

        [Test]
        public void OnPostMapRequestHandler_FormStateAndCookiePointerStored_RestoreHandlerIsPassedFormState()
        {
            using (var context = Setup.TestContext<WebTestContext>()
                .Create())
            {
                context.RequestMock.Object.Form.Add("myField", "myValue");
                FormState state = FormState.Create(context.HttpContextMock.Object);
                var sut = new FormStateKeeperModuleForTest();
                sut.OnInit("loginUrl", "formsAuthCookieName");
                context.RequestMock.Object.Cookies.Add(new HttpCookie(sut.CookieName, state.StateId));

                sut.OnPostMapRequestHandler(context.HttpContextMock.Object);
                
                Assert.NotNull(context.HttpContextMock.Object.Handler);
                Assert.IsInstanceOf<FormStateRestoreHandler>(context.HttpContextMock.Object.Handler);
                Assert.AreEqual(state, ((FormStateRestoreHandler) context.HttpContextMock.Object.Handler).FormState);
            }
        }
    }
}